package com.zlq.login.util;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 数据库工具类
 * 提供了获取连接的公共方法
 * 提供了做增删改的公共方法
 * 提供了做查询操作的公共方法
 * 提供了关闭所有数据库资源的公共方法
 * @author Administrator
 *
 */
public class DBUtil {
	
	private static String className;
	private static String url;
	private static String user;
	private static String password;
	
	//静态代码块完成了属性文件的读取和驱动的加载
	static{
		try {
			//1、把数据库连接参数参数
			Properties pops = new Properties();
			//把jdbc.properties中的数据库连接参数读取出来存放在Properties对象中
			pops.load(DBUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"));
			//从Properties对象按照键获取对应的属性值
			className=pops.getProperty("jdbc.mysql.className");
			url = pops.getProperty("jdbc.mysql.url");
			user = pops.getProperty("jdbc.mysql.user");
			password = pops.getProperty("jdbc.mysql.password");
			
			//2、加载数据库驱动
			Class.forName(className);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 公共的获取数据库连接的方法
	 * @return -获取到数据库连接
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException{
		Connection conn = DriverManager.getConnection(url, user, password);
		return conn;
	}
	
	/**
	 * 释放数据库资源
	 * @param rs -结果集对象，如果不需要关闭该资源传入null
	 * @param stmt -语句对象，如果不需要关闭该资源传入null
	 * @param conn -连接对象，如果不需要关闭该资源传入null
	 * @throws SQLException
	 */
	public static void close(ResultSet rs, Statement  stmt,Connection  conn) throws SQLException{
		if(rs!=null){
			rs.close();
		}
		if(stmt!=null){
			stmt.close();
		}
		if(conn!=null){
			conn.close();
		}
	}
	
	/**
	 * 增删改公共通用方法
	 * @param sql -增删改对应的sql语句
	 * @return
	 */
	public static int update(String sql){
		return update(sql,null);
	}
	
	/**
	 * 增删改的公共通用方法
	 * @param sql -增删改对应的sql语句
	 * @param args -为占位符设置的参数，如果不需要参数可以传递null或者数据长度为0数组
	 * @return
	 */
	public static int update(String sql,Object[] args){
		Connection conn = null;
		PreparedStatement ps = null;
		int rows = 0;
		
		try {
			conn = getConnection();
			ps = conn.prepareStatement(sql);
			//如果数组不为null且长度大于0说明sql语句中有？占位符
			if(args!=null && args.length>0){
				//需要将数组中的元素设置分别设置给占位符
				for(int i=0;i<args.length;i++){
					ps.setObject(i+1, args[i]);
				}
			}
			
			rows = ps.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			try {
				close(null, ps, conn);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return rows;
	}

	
	/**
	 * 通用的查询方法
	 * @param sql -查询语句
	 * @return -将查询到每行数据的多列存放到Map集合中，以列名作为键，以列值作为值，将保持一行中多列数据的Map集合放在List集合中返回
	 */
	public static List<Map<String,String>> query(String sql){
		return query(sql,new Object[]{});
	}
	
	/**
	 * 查询通用方法
	 * @param sql -执行查询的sql语句
	 * @param args -为sql语句中占位符?设置的值数组，该数组允许为null值，如果为null或者数组长度为0则视为sql参数中不包含?占位符
	 * @return -将查询到每行数据的多列存放到Map集合中，以列名作为键，以列值作为值，将保持一行中多列数据的Map集合放在List集合中返回
	 */
	public static List<Map<String,String>> query(String sql,Object... args){
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<Map<String,String>> list = new ArrayList<Map<String,String>>();
		
		try {
			conn = getConnection();
			ps = conn.prepareStatement(sql);
			//为sql语句中的?占位符设置值
			if(args!=null && args.length>0){
				for(int i=0;i<args.length;i++){
					ps.setObject(i+1, args[i]);
				}
			}
			rs = ps.executeQuery();
			//查询结果的中包含几列，每一列的数据类型 每一列的列名这些信息都封装到ResultSetMetaData对象中
			ResultSetMetaData rsmd = rs.getMetaData();
			//获取到查询结果中包含了几列
			int count = rsmd.getColumnCount();
			
			while(rs.next()){
				//取出当前行的每一列 因为该方法是通用方法，所以在定义方法无法获取用户需要查询多少列数据，在这想要完成这个功能，需要知道我们这次查询查询几列，每一列的列名是什么
				HashMap<String, String> map = new HashMap<String, String>();
				for(int i=1;i<=count;i++){
					//取出每一列的列名
					String cname = rsmd.getColumnLabel(i);
					//取出每一列的值
					String cvalue = rs.getString(cname);
					map.put(cname, cvalue);
				}
				//把这一行数据放置到List集合中
				list.add(map);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			try {
				close(rs,ps,conn);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
}
